using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TrafficTrouble.Core;
using System.IO;
using Microsoft.Xna.Framework;

namespace TrafficTrouble
{
    [System.Diagnostics.DebuggerNonUserCode]
    public static class Util
    {
        public static int Width<T>(this T[,] array)
        {
            return array.GetLength(0);
        }
        public static int Height<T>(this T[,] array)
        {
            return array.GetLength(1);
        }

        public static string ReplaceCharAt(this string str, int index, char newChar)
        {
            string st = str.Remove(index);
            st = new string(new char[] { newChar });
            st = str.Substring(index + 1);
            return str.Remove(index) + newChar + str.Substring(index + 1);
        }

        public static T[] Map<T>(this T[] array, Func<T, T> map)
        {
            T[] mapped = new T[array.Length];
            for (int i = 0; i < array.Length; i++)
                mapped[i] = map(array[i]);
            return mapped;
        }

        public static bool Contains(this Rectangle rect, Vector2 point)
        {
            return point.X >= rect.X && point.X < rect.X + rect.Width
                && point.Y >= rect.Y && point.Y < rect.Y + rect.Height;
        }
    }

    [System.Diagnostics.DebuggerNonUserCode]
    public struct Tuple<T1, T2>
    {
        private T1 _item1;
        public T1 Item1 { get { return this._item1; } }

        private T2 _item2;
        public T2 Item2 { get { return this._item2; } }

        public Tuple(T1 item1, T2 item2)
        {
            this._item1 = item1;
            this._item2 = item2;
        }

        public static bool operator ==(Tuple<T1, T2> tuple1, Tuple<T1, T2> tuple2)
        {
            return tuple1.Item1.Equals(tuple2.Item1) && tuple1.Item2.Equals(tuple2.Item2);
        }
        public static bool operator !=(Tuple<T1, T2> tuple1, Tuple<T1, T2> tuple2)
        {
            return !(tuple1 == tuple2);
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Tuple<T1, T2>)) return false;
            return this == (Tuple<T1, T2>)obj;
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return "[" + this.Item1.ToString() + ", " + this.Item2.ToString() + "]";
        }
    }

    public struct BitField
    {
        private const int BITS_IN_BYTE = 8;

        private byte[] Bytes;
        public bool this[int index]
        {
            get
            {
                if (index < 0 || index >= this.Count)
                    throw new ArgumentOutOfRangeException("index");
                //              | = 11
                //  76543210|76543210
                int byteIndex = index / BITS_IN_BYTE;
                int bitIndex = index % BITS_IN_BYTE;

                byte b = this.Bytes[byteIndex];
                byte shifted = (byte)((b << bitIndex) >> (BITS_IN_BYTE - 1));
                return shifted != 0;
            }
            set
            {
                if (index < 0 || index >= this.Count)
                    throw new ArgumentOutOfRangeException("index");

                int byteIndex = index / BITS_IN_BYTE;
                int bitIndex = index % BITS_IN_BYTE;

                byte b = this.Bytes[byteIndex];
                byte mask = (byte)(1 << (BITS_IN_BYTE - bitIndex - 1));
                byte newByte = (byte)(value ? (b | mask) : (b & ~mask));
                this.Bytes[byteIndex] = newByte;
            }
        }

        private int _count;
        public int Count { get { return _count; } private set { _count = value; } }

        public BitField(int numBools)
        {
            if (numBools < 0) numBools = 0;
            _count = numBools;

            if (numBools % BITS_IN_BYTE != 0)
                numBools += BITS_IN_BYTE - (numBools % BITS_IN_BYTE);
            int numBytes = numBools / BITS_IN_BYTE;

            Bytes = new byte[numBytes];
        }
        public BitField(bool[] bools)
        {
            _count = bools.Length;
            Bytes = new byte[_count];
            for (int i = 0; i < bools.Length; i++)
                this[i] = bools[i];
        }
    }
}
